package dream

import (
	"bytes"
	"encoding/binary"
	"errors"
	"net"
	"time"
	"unsafe"
)

func isValidHenlen(settingheadlen int) bool {
	if settingheadlen == 1 || settingheadlen == 2 || settingheadlen == 4 || settingheadlen == 137 {
		return true
	}
	return false
}

func tryRecv(c net.Conn, buf []byte, timeouts uint32) (int, error) {
	head := 0
	tail := len(buf)
	c.SetReadDeadline(time.Now().Add(time.Duration(timeouts) * time.Second))
	readed, err := c.Read(buf[head:tail])
	if err != nil {
		return readed, err
	}
	return readed, nil
}
func loopRecv(c net.Conn, buf []byte, timeouts uint32) error {
	head := 0
	tail := len(buf)
	for head < tail {
		c.SetReadDeadline(time.Now().Add(time.Duration(timeouts) * time.Second))
		readed, err := c.Read(buf[head:tail])
		if err != nil {
			return err
		}
		head += readed
	}
	return nil
}

func recvPackageHeader(c net.Conn, settingheadlen int, timeouts uint32, tempheader []byte) (uint32, error) {
	if settingheadlen == 137 {
		err := loopRecv(c, tempheader[0:1], timeouts)
		if err != nil {
			return 0, err
		}
		var blen uint8
		io := bytes.NewBuffer(tempheader[0:1])
		binary.Read(io, binary.BigEndian, &blen)
		if blen == 0xff {
			err := loopRecv(c, tempheader[1:3], timeouts)
			if err != nil {
				return 0, err
			}
			var slen uint16
			io = bytes.NewBuffer(tempheader[1:3])
			binary.Read(io, binary.LittleEndian, &slen)
			if slen == 0xffff {
				err := loopRecv(c, tempheader[3:7], timeouts)
				if err != nil {
					return 0, err
				}
				var ilen uint32
				io = bytes.NewBuffer(tempheader[3:7])
				binary.Read(io, binary.BigEndian, &ilen)
				return ilen, nil
			} else {
				return uint32(slen), nil
			}
		} else {
			return uint32(blen), nil
		}
	} else if settingheadlen == 1 {
		err := loopRecv(c, tempheader[0:1], timeouts)
		if err != nil {
			return 0, err
		}
		var blen uint8
		io := bytes.NewBuffer(tempheader[0:1])
		binary.Read(io, binary.BigEndian, &blen)
		return uint32(blen), nil
	} else if settingheadlen == 2 {
		err := loopRecv(c, tempheader[0:2], timeouts)
		if err != nil {
			return 0, err
		}
		var slen uint16
		io := bytes.NewBuffer(tempheader[0:2])
		binary.Read(io, binary.LittleEndian, &slen)
		return uint32(slen), nil
	} else if settingheadlen == 4 {
		err := loopRecv(c, tempheader[0:4], timeouts)
		if err != nil {
			return 0, err
		}
		var ilen uint32
		io := bytes.NewBuffer(tempheader[0:4])
		binary.Read(io, binary.BigEndian, &ilen)
		return ilen, nil
	} else {
		return 255, nil
	}
}

func loopSend_2019_12_26(c net.Conn, buf []byte, timeouts uint32) error {
	head := 0
	tail := len(buf)
	c.SetWriteDeadline(time.Now().Add(time.Duration(timeouts) * time.Second))
	if head < 1 {
		writed, err := c.Write(buf[head:1])
		if err != nil {
			return err
		}
		/*if writed==0 {
			return errors.New("writed zero")
		}*/
		head += writed
	}
	for head < tail {
		writed, err := c.Write(buf[head:tail])
		if err != nil {
			Logi(LOG_KERL, "loopSend_2019_12_26 检测出连接已断开 ", err)
			return err
		}
		/*if writed==0 {
			return errors.New("writed zero")
		}*/
		head += writed
	}
	return nil
}

func loopSend(c net.Conn, buf []byte, timeouts uint32) error {
	head := 0
	tail := len(buf)
	for head < tail {
		c.SetWriteDeadline(time.Now().Add(time.Duration(timeouts) * time.Second))
		writed, err := c.Write(buf[head:tail])
		if err != nil {
			return err
		}
		/*if writed==0 {
			return errors.New("writed zero")
		}*/
		head += writed
	}
	return nil
}

func sendAPackage(c net.Conn, withXY bool, xy XY, buf []byte, settingheadlen int, timeouts uint32, tempheader []byte) error {
	io := bytes.NewBuffer(tempheader)
	tlen := uint(len(buf))
	if withXY {
		tlen += uint(unsafe.Sizeof(xy))
	}
	if settingheadlen == 137 {
		if tlen < 0xff {
			binary.Write(io, binary.BigEndian, byte(tlen))
		} else if tlen < 0xffff {
			binary.Write(io, binary.BigEndian, byte(0xff))
			binary.Write(io, binary.BigEndian, uint16(tlen))
		} else if tlen < 0xffffffff {
			binary.Write(io, binary.BigEndian, byte(0xff))
			binary.Write(io, binary.BigEndian, uint16(0xffff))
			binary.Write(io, binary.BigEndian, uint32(tlen))
		} else { //err pack
			Assert(false, "MyClient:send 137 limit")
			return errors.New("Send Limit")
		}
		err := loopSend(c, tempheader[0:0+io.Len()], timeouts) //0 pack
		if err != nil {
			return err
		}
	} else if settingheadlen == 1 {
		if tlen > 0xff { //err pack
			Assert(false, "MyClient:send 1 limit")
			return errors.New("Send Limit")
		}
		binary.Write(io, binary.BigEndian, byte(tlen))
		err := loopSend(c, tempheader[0:0+1], timeouts)
		if err != nil {
			return err
		}
	} else if settingheadlen == 2 {
		if tlen > 0xffff { //err pack
			Assert(false, "MyClient:send 2 limit")
			return errors.New("Send Limit")
		}
		binary.Write(io, binary.LittleEndian, uint16(tlen))
		err := loopSend(c, tempheader[0:0+2], timeouts)
		if err != nil {
			return err
		}
	} else if settingheadlen == 4 {
		if tlen > 0xffffffff { //err pack
			Assert(false, "MyClient:send 4 limit")
			return errors.New("Send Limit")
		}
		binary.Write(io, binary.BigEndian, uint32(tlen))
		err := loopSend(c, tempheader[0:0+2], timeouts)
		if err != nil {
			return err
		}
	}
	if withXY {
		//
	}
	if len(buf) > 0 { //normal pack
		err := loopSend(c, buf, timeouts)
		if err != nil {
			return err
		}
	}
	return nil
}

func init() {
}

func allocPack(len uint32) []byte {
	tempheader := make([]byte, len)
	return tempheader
}

func allocPackWithInstall(withXY bool, xy XY, buf []byte, settingheadlen int) []byte {
	tempheader := make([]byte, 7+int(unsafe.Sizeof(xy))+len(buf))
	io := bytes.NewBuffer(tempheader)
	io.Reset()
	tlen := uint(len(buf))
	if withXY {
		tlen += uint(unsafe.Sizeof(xy))
	}
	if settingheadlen == 137 {
		if tlen < 0xff {
			binary.Write(io, binary.BigEndian, byte(tlen))
		} else if tlen < 0xffff {
			binary.Write(io, binary.BigEndian, byte(0xff))
			binary.Write(io, binary.BigEndian, uint16(tlen))
		} else if tlen < 0xffffffff {
			binary.Write(io, binary.BigEndian, byte(0xff))
			binary.Write(io, binary.BigEndian, uint16(0xffff))
			binary.Write(io, binary.BigEndian, uint32(tlen))
		} else { //err pack
			Assert(false, "MyClient:send 137 limit")
			panic(0)
		}
	} else if settingheadlen == 1 {
		if tlen > 0xff { //err pack
			Assert(false, "MyClient:send 1 limit")
			panic(0)
		}
		binary.Write(io, binary.BigEndian, byte(tlen))
	} else if settingheadlen == 2 {
		if tlen > 0xffff { //err pack
			Assert(false, "MyClient:send 2 limit")
			panic(0)
		}
		binary.Write(io, binary.LittleEndian, uint16(tlen))
	} else if settingheadlen == 4 {
		if tlen > 0xffffffff { //err pack
			Assert(false, "MyClient:send 4 limit")
			panic(0)
		}
		binary.Write(io, binary.BigEndian, uint32(tlen))
	} else {

	}
	if withXY {
		binary.Write(io, binary.LittleEndian, xy)
	}
	if len(buf) > 0 { //normal pack
		binary.Write(io, binary.BigEndian, buf)
	}
	return tempheader[0:io.Len()]
}

func freePack(p []byte) {
}

func SendPackAndRecv(sock net.Conn, headertemp []byte, pack []byte) ([]byte, error) {
	buf := allocPackWithInstall(false, 0, pack, 137)
	err := loopSend_2019_12_26(sock, buf, 10)
	if err != nil {
		return nil, err
	} else {
		var tlen uint32
		tlen, err = recvPackageHeader(sock, 137, 10, headertemp)
		if err == nil {
			var pack []byte = make([]byte, tlen)
			if tlen > 0 {
				if isValidHenlen(137) {
					err = loopRecv(sock, pack, 10)
				}
				return pack, err
			} else {
				var read int
				read, err = tryRecv(sock, pack, 10)
				pack = pack[0:read]
				return pack, err
			}
		} else {
			return nil, err
		}
	}
}
